package org.duang.plugins;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.duang.event.EventHandler;
import org.duang.event.EventUtil;
import org.duang.event.core.DuangEventListener;
import org.duang.kit.BeanKit;
import org.duang.kit.MultiMaps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class EventPlugin implements IPlugin{

	private static Logger logger = LoggerFactory.getLogger(EventPlugin.class);
	
	private final int THREADPOOL_NUMBER = 10;
	private final MultiMaps<Type, DuangEventListener> multiMaps;
	private EventHandler eventHandler = null;
	private ExecutorService eventPool = null;
	
	public EventPlugin() {
		multiMaps = new MultiMaps<Type, DuangEventListener>();
	}
	
	public EventPlugin isAsync(boolean async) {
		return isAsync(async, THREADPOOL_NUMBER);
	}
	
	public EventPlugin isAsync(boolean async, int nThreads) {
		if(async){
			eventPool = Executors.newFixedThreadPool(nThreads);
		}
		return this;
	}
	
	@SuppressWarnings({ "null", "unchecked" })
	public void start() throws Exception {
		try{
		MultiMaps<Type, DuangEventListener> map = new MultiMaps<Type, DuangEventListener>();
		Type type = null; DuangEventListener listener = null;
		for(Iterator<Entry<Class<?>, Object>> it = BeanKit.getBeanMap().entrySet().iterator(); it.hasNext();) {
			Entry<Class<?>,Object> entry = it.next();
			// 实例化监听器
			listener = (DuangEventListener)entry.getValue();
			Class<? extends DuangEventListener> clazz = listener.getClass();
			if (DuangEventListener.class.isAssignableFrom(clazz) && !clazz.equals(DuangEventListener.class)) {
				// 获取监听器上的泛型信息
				type = ((ParameterizedType) clazz.getGenericInterfaces()[0]).getActualTypeArguments()[0];
				map.put(type, listener);
			}
		}
		
		for(Iterator<Entry<Type, List<DuangEventListener>>> it = map.entrySet().iterator(); it.hasNext();){
			Entry<Type, List<DuangEventListener>> entry = it.next();
			List<DuangEventListener> list = entry.getValue();
			java.util.Collections.sort(list, new Comparator(){
				@Override
				public int compare(Object o1, Object o2) {
					int order1 = ((DuangEventListener)o1).getOrder();
					int order2 = ((DuangEventListener)o2).getOrder();
					if(order1 > order2){
						return 1;
					} else if (order1 < order2){
						return -1;
					} else {
						return 0;
					}
				}
			});
			for(DuangEventListener subListener : list){
				multiMaps.put(entry.getKey(), subListener);
			}
		}
		eventHandler = new EventHandler(multiMaps, eventPool);
		EventUtil.init(eventHandler);
		}catch(Exception e) {
			e.printStackTrace();
		}
	}

	public void stop() throws Exception {
		multiMaps.clear();
		if (null != eventPool) {
			eventPool.shutdown();
		}
		eventPool = null;
		eventHandler = null;
	}

}
